home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / wil4c10.zip / NEWS.C < prev    next >
C/C++ Source or Header  |  1997-07-26  |  17KB  |  588 lines

  1. /*
  2. **  --- news.c ---
  3. **
  4. **  This program can:
  5. **
  6. **  (1) List all newsgroups.
  7. **  (2) Select a news group.
  8. **  (3) Get article head from selected newsgroup.
  9. **  (4) Get article body from selected newsgroup.
  10. **
  11. **  Articles (specified by article number) are saved
  12. **  to disk with extension ".ART".
  13. **
  14. **  The group list (LIST command) is saved to NEWS.LST
  15. **
  16. **  You must be authenicated with the news service you connect to.
  17. */
  18.  
  19. #include <windows.h>
  20. #include <winsock.h>
  21.  
  22. #include "wil.h"
  23. #include "message.h"
  24.  
  25. #include "about.h"
  26. #include "paint.h"
  27. #include "str.h"
  28. #include "async.h"
  29.  
  30. #ifdef WIN32
  31. #define USE_INS HINSTANCE
  32. #define USE_PTR PSTR
  33. #else
  34. #define USE_INS HANDLE
  35. #define USE_PTR LPSTR
  36. #endif
  37.  
  38. LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
  39.  
  40. /* globals */
  41.  
  42. HWND hMainWnd;            /* main window handle */
  43.  
  44. #define BS            8
  45. #define LF           10
  46. #define CR           13
  47. #define ESC          27
  48.  
  49. #define MAX_BUF     128
  50. #define STR_SIZE     40
  51. #define NNTP_PORT   119
  52. #define ONE_SEC    1000
  53. #define QUOTE      0x22
  54.  
  55. /* messages generated by calling PostMessage() [see POST_MSG below] */
  56.  
  57. #define USER_CONNECT       101
  58. #define USER_CONN_SUCCESS  102
  59. #define USER_CONN_FAILURE  103
  60.  
  61. #define USER_LIST          201
  62. #define USER_LIST_READ_OK  202
  63. #define USER_GROUP         301
  64. #define USER_HEADER        401
  65. #define USER_ARTICLE       501
  66. #define USER_ART_READ_OK   502
  67.  
  68. #define USER_QUIT_SUCCESS  601
  69.  
  70. #define USER_COMMAND_SUCCESS 1001
  71. #define USER_COMMAND_FAILURE 1002
  72.  
  73. /* menu bar postions (order must match items in NEWS.RC) */
  74.  
  75. #define MENU_EXIT     0
  76. #define MENU_CONNECT  1
  77. #define MENU_GROUP    2
  78. #define MENU_HEADER   3
  79. #define MENU_ARTICLE  4
  80. #define MENU_QUIT     5
  81. #define MENU_BREAK    6
  82. #define MENU_ABOUT    7
  83.  
  84. /* private */
  85.  
  86. static int ConnectedFlag = 0;           /* TRUE when connected */
  87. static USE_INS hInstance;               /* instance variable */
  88. static int WinWidth = 8 * NCOLS;        /* width in pixels */
  89. static int WinHeight = 15 * NROWS;      /* height in pixels */
  90. static int EchoFlag = 1;                /* echo commands if TRUE */
  91. static char Temp[MAX_BUF+8];            /* temporary buffer */
  92. static int  InBufLen = 0;               /* length of string in InBuffer[] */
  93. static int  InBufCmd = 0;               /* command */
  94. static char InBuffer[MAX_BUF+1];        /* input buffer */
  95. static SOCKET TheSocket = (SOCKET)-1;   /* the socket */
  96. static HCURSOR ArrowCursor;             /* arrow cursor */
  97. static HCURSOR WaitCursor;              /* hour glass cursor */
  98.  
  99. /* enable menu bar item */
  100.  
  101. void EnableMenuBarItems(int nPos1, int nPos2)
  102. {int i;
  103.  HMENU hMenu;
  104.  hMenu = GetMenu(hMainWnd);
  105.  for(i=nPos1;i<=nPos2;i++)
  106.    EnableMenuItem(hMenu,i,MF_BYPOSITION | MF_ENABLED);
  107.  DrawMenuBar(hMainWnd);
  108. }
  109.  
  110. /* disable menu bar item */
  111.  
  112. void DisableMenuBarItems(int nPos1, int nPos2)
  113. {int i;
  114.  HMENU hMenu;
  115.  hMenu = GetMenu(hMainWnd);
  116.  for(i=nPos1;i<=nPos2;i++)
  117.    EnableMenuItem(hMenu,i,MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
  118.  DrawMenuBar(hMainWnd);
  119. }
  120.  
  121. /* menu state when not connected, awaiting user input */
  122.  
  123. void NotConnectedMenuState(void)
  124. {EnableMenuBarItems(MENU_CONNECT, MENU_CONNECT);
  125.  DisableMenuBarItems(MENU_GROUP, MENU_BREAK);
  126. }
  127.  
  128. /* menu state when connected, awaiting user input */
  129.  
  130. void ConnectedMenuState(void)
  131. {DisableMenuBarItems(MENU_CONNECT, MENU_CONNECT);
  132.  EnableMenuBarItems(MENU_GROUP, MENU_BREAK);
  133. }
  134.  
  135. /* menu state while executing NNTP command */
  136.  
  137. void DoingCmdMenuState(void)
  138. {DisableMenuBarItems(MENU_CONNECT, MENU_QUIT);
  139.  EnableMenuBarItems(MENU_BREAK, MENU_BREAK);
  140. }
  141.  
  142. /* add character to input buffer */
  143.  
  144. static void Add2Buffer(char Chr)
  145. {int i;
  146.  /* add char to input buffer */
  147.  switch(Chr)
  148.    {case BS:
  149.       if(InBufLen>0)
  150.         {/* backup on screen */
  151.          DisplayChar(BS);
  152.          /* remove last char from buffer */
  153.          InBufLen--;
  154.         }
  155.       break;
  156.     case ESC:
  157.       for(i=1;i<=InBufLen;i++) DisplayChar(BS);
  158.       InBufLen = 0;
  159.       DestroyCaret();
  160.       break;
  161.     default:
  162.       /* display char */
  163.       DisplayChar(Chr);
  164.       /* put into buffer */
  165.       if(InBufLen<MAX_BUF) InBuffer[InBufLen++] = Chr;
  166.       break;
  167.    }
  168. }
  169.  
  170. /* place the cursor in the display window */
  171.  
  172. static void SetTheFocus(void)
  173. {/* create client area caret */
  174.  CreateCaret(hMainWnd,NULL,3,10);
  175.  SetCaretPos(PaintGetColPos(),PaintGetRowPos());
  176.  ShowCaret(hMainWnd);
  177. }
  178.  
  179. /* display error message */
  180.  
  181. static void DisplayError(int Code, LPSTR Msg)
  182. {DisplayString("ERROR: ");
  183.  if(Msg) DisplayString(Msg);
  184.  if(Code)
  185.    {wilErrorText(Code,(LPSTR)Temp,50);
  186.     DisplayLine((LPSTR)Temp);
  187.    }
  188. }
  189.  
  190. /* WinMain */
  191.  
  192. #ifdef WIN32
  193. int WINAPI
  194. #else
  195. int PASCAL
  196. #endif
  197. WinMain(USE_INS hInst, USE_INS hPrevInstance,
  198.         USE_PTR szCmdLine,  int nCmdShow)
  199. {WNDCLASS  wc;
  200.  MSG msg;
  201.  BOOL Result;
  202.  if(!hPrevInstance)
  203.    {/* register main window class */
  204.     wc.style = CS_HREDRAW | CS_VREDRAW;
  205.     wc.lpfnWndProc = MainWndProc;
  206.     wc.cbClsExtra = 0;
  207.     wc.cbWndExtra = 0;
  208.     wc.hInstance = hInst;
  209.     wc.hIcon = LoadIcon(hInst, "HostIcon");
  210.     wc.hCursor = NULL;
  211.     wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  212.     wc.lpszMenuName =  "HostMenu";
  213.     wc.lpszClassName = "HostWClass";
  214.     Result = RegisterClass(&wc);
  215.     if(!Result) return FALSE;
  216.    }
  217.  
  218.  /* create main window */
  219.  hInstance = hInst;
  220.  hMainWnd = CreateWindow(
  221.         "HostWClass",   "News",    WS_OVERLAPPEDWINDOW,
  222.         CW_USEDEFAULT,  CW_USEDEFAULT,
  223.         WinWidth,       WinHeight,
  224.         NULL,           NULL,
  225.         hInstance,      NULL);
  226.  ShowWindow(hMainWnd, nCmdShow);
  227.  UpdateWindow(hMainWnd);
  228.  
  229.  /* window control loop */
  230.  
  231.  while(GetMessage(&msg,NULL,0,0))
  232.    {
  233.     TranslateMessage(&msg);
  234.     DispatchMessage(&msg);
  235.    }
  236.  return (msg.wParam);
  237. } /* end WinMain */
  238.  
  239. #ifdef WIN32
  240. LRESULT CALLBACK
  241. #else
  242. long FAR PASCAL
  243. #endif
  244. MainWndProc(HWND hWindow,UINT iMsg,WPARAM wParam,LPARAM lParam)
  245. {int Code;
  246.  HDC hDC;
  247.  PAINTSTRUCT ps;
  248.  static LPSTR BufferPtr;
  249.  static int  Handle = 0;
  250.  static char FileName[32];
  251.  ULONG Article;
  252. #ifdef WIN32
  253. #else
  254.  static FARPROC lpfnAboutDlgProc;
  255. #endif
  256.  hMainWnd = hWindow;
  257.  switch (iMsg)
  258.    {case WM_CREATE:
  259.       /* create cursors */
  260.       ArrowCursor = LoadCursor(NULL, IDC_ARROW);
  261.       WaitCursor = LoadCursor(NULL, IDC_WAIT);
  262.       SetCursor(ArrowCursor);
  263. #ifdef WIN32
  264. #else
  265.       /* create thunk for Win16 */
  266.       lpfnAboutDlgProc = MakeProcInstance(AboutDlgProc,hInstance);
  267. #endif
  268.       /* initialize paint module */
  269.       PaintInit();
  270.       /* attach WINSOCK */
  271.       DisplayString("Attaching WINSOCK...");
  272.       Code = wilAttach();
  273.       DisplayLine("OK");
  274.       if(Code<0) DisplayError(Code,"wilAttach fails:");
  275.       else
  276.         {wsprintf((LPSTR)Temp," Description: %s", wilGetDescription() );
  277.          DisplayLine((LPSTR)Temp);
  278.          wsprintf((LPSTR)Temp," My HostName: %s", wilGetMyHostName() );
  279.          DisplayLine((LPSTR)Temp);
  280.          wsprintf((LPSTR)Temp," My HostAddr: %s", wilGetMyHostDotted(0) );
  281.          DisplayLine((LPSTR)Temp);
  282.         }
  283.       /* initialize menus */
  284.       NotConnectedMenuState();
  285.       break;
  286.  
  287.     case WM_COMMAND:
  288.       switch(wParam)
  289.         {
  290.          case MSG_ABOUT :
  291. #ifdef WIN32
  292.            DialogBox(hInstance, "AboutBox", hMainWnd, AboutDlgProc);
  293. #else
  294.            DialogBox(hInstance, "AboutBox", hMainWnd, lpfnAboutDlgProc);
  295. #endif
  296.            return 0;
  297.  
  298.          case MSG_DEBUG:
  299.             SetCursor(WaitCursor);
  300.             break;
  301.  
  302.          case MSG_ECHO:
  303.             EchoFlag = 1 - EchoFlag;
  304.             DisplayString("Echo flag is now ");
  305.             if(EchoFlag) DisplayLine("ON");
  306.             else DisplayLine("OFF");
  307.             break;
  308.  
  309.          case MSG_BREAK:
  310.             if(ConnectedFlag) ConnectedMenuState();
  311.             else NotConnectedMenuState();
  312.             /* cancel any async events */
  313.             wilAwaitCancel(TheSocket, hMainWnd);
  314.             /* cancel any blocking */
  315.             wilCancelBlocking();
  316.             break;
  317.  
  318.          case MSG_EXIT:
  319.             wilRelease();
  320.             DestroyWindow(hMainWnd);
  321.             break;
  322.  
  323.          case MSG_NEWS_CONNECT:
  324.             InBufCmd = USER_CONNECT;
  325.             DisableMenuBarItems(MENU_CONNECT, MENU_QUIT);
  326.             DisplayString("Enter NNTP server name:");
  327.             InBufLen = 0;
  328.             SetTheFocus();
  329.             break;
  330.  
  331.          case MSG_NEWS_LIST:
  332.             InBufCmd = USER_LIST;
  333.             DisableMenuBarItems(MENU_CONNECT, MENU_QUIT);
  334.             POST_MSG(USER_LIST);
  335.             break;
  336.  
  337.          case MSG_NEWS_GROUP:
  338.             InBufCmd = USER_GROUP;
  339.             DisableMenuBarItems(MENU_CONNECT, MENU_QUIT);
  340.             DisplayString("Enter news group:");
  341.             InBufLen = 0;
  342.             SetTheFocus();
  343.             break;
  344.  
  345.          case MSG_NEWS_HEADER_BYNUMBER:
  346.             InBufCmd = USER_HEADER;
  347.             DisableMenuBarItems(MENU_CONNECT, MENU_QUIT);
  348.             DisplayString("Enter (article) header number:");
  349.             InBufLen = 0;
  350.             SetTheFocus();
  351.             break;
  352.  
  353.          case MSG_NEWS_HEADER_CURRENT:
  354.             /* send HEAD command, expect multiple text lines back */
  355.             AsyncCommand("HEAD", USER_COMMAND_SUCCESS, USER_COMMAND_FAILURE,
  356.                          ASYNC_MULTIPLE_LINES);
  357.             break;
  358.  
  359.          case MSG_NEWS_HEADER_NEXT:
  360.          case MSG_NEWS_ARTICLE_NEXT:
  361.             /* send NEXT command, expect single text line back */
  362.             AsyncCommand("NEXT", USER_COMMAND_SUCCESS, USER_COMMAND_FAILURE,
  363.                          ASYNC_SINGLE_LINE);
  364.             break;
  365.  
  366.          case MSG_NEWS_HEADER_LAST:
  367.          case MSG_NEWS_ARTICLE_LAST:
  368.             /* send LAST command, expect single text line back */
  369.             AsyncCommand("LAST", USER_COMMAND_SUCCESS, USER_COMMAND_FAILURE,
  370.                          ASYNC_SINGLE_LINE);
  371.             break;
  372.  
  373.          case MSG_NEWS_ARTICLE_BYNUMBER:
  374.             InBufCmd = USER_ARTICLE;
  375.             DisableMenuBarItems(MENU_CONNECT, MENU_QUIT);
  376.             DisplayString("Enter article number:");
  377.             InBufLen = 0;
  378.             SetTheFocus();
  379.             break;
  380.  
  381.          case MSG_NEWS_ARTICLE_CURRENT:
  382.             /* send ARTICLE command, expect multiple text lines back */
  383.             AsyncCommand("ARTICLE", USER_COMMAND_SUCCESS, USER_COMMAND_FAILURE,
  384.                          ASYNC_MULTIPLE_LINES);
  385.             break;
  386.  
  387.          case MSG_NEWS_QUIT:
  388.             /* send QUIT to news server */
  389.             AsyncCommand("QUIT", USER_QUIT_SUCCESS, USER_COMMAND_FAILURE,
  390.                          ASYNC_SINGLE_LINE);
  391.             break;
  392.  
  393.         }
  394.       break;
  395.  
  396.     case WM_USER: /* posted by WIL */
  397.       AsyncProcessMsg(lParam);
  398.       break;
  399.  
  400.     case WM_USER+1:
  401.  
  402.       switch(wParam)
  403.         {
  404.          case USER_CONNECT:
  405.            if(lstrlen((LPSTR)InBuffer)==0)
  406.              {DisplayError(0,"Missing server name");
  407.               break;
  408.              }
  409.            /* waiting for connection */
  410.            DoingCmdMenuState();
  411.            SetCursor(WaitCursor);
  412.            TheSocket = AsyncConnect(hMainWnd,"NNTP",(LPSTR)InBuffer,
  413.                                     NNTP_PORT, USER_CONN_SUCCESS,
  414.                                     USER_CONN_FAILURE, ASYNC_SINGLE_LINE);
  415.            break;
  416.  
  417.          case USER_CONN_SUCCESS:
  418.            DisplayLine("CONNECT successful");
  419.            ConnectedMenuState();
  420.            SetCursor(ArrowCursor);
  421.            break;
  422.  
  423.          case USER_CONN_FAILURE:
  424.            DisplayLine("CONNECT fails");
  425.            NotConnectedMenuState();
  426.            SetCursor(ArrowCursor);
  427.            break;
  428.  
  429.          /* list groups */
  430.  
  431.          case USER_LIST:
  432.            SetCursor(WaitCursor);
  433.            /* open file for list */
  434.            Handle = _lcreat((LPSTR)"NEWS.LST",0);
  435.            if(Handle<0)
  436.              {DisplayLine("Cannot create NEWS.LST");
  437.               Handle = 0;
  438.               POST_MSG(USER_COMMAND_FAILURE);
  439.               break;
  440.              }
  441.            DisplayLine("Saving list to NEWS.LST");
  442.            /* send LIST command, expect multiple text lines back */
  443.            AsyncCommand("LIST", USER_LIST_READ_OK, USER_COMMAND_FAILURE,
  444.                         ASYNC_SINGLE_LINE);
  445.            break;
  446.  
  447.          case USER_LIST_READ_OK:
  448.            /* read was successfull */
  449.            BufferPtr = AsyncGetBufPtr();
  450.            /* check if this is the last line */
  451.            if((*BufferPtr=='.')&&(*(BufferPtr+1)=='\r') )
  452.              {/* end of list */
  453.               DisplayLine("[END]");
  454.               POST_MSG(USER_COMMAND_SUCCESS);
  455.               break;
  456.              }
  457.            /* write to disk */
  458.            _lwrite(Handle, (LPSTR)BufferPtr, lstrlen((LPSTR)BufferPtr) );
  459.            /* read next line */
  460.            AsyncRead(USER_LIST_READ_OK, USER_COMMAND_FAILURE, ASYNC_SINGLE_LINE);
  461.            break;
  462.  
  463.          /* set group */
  464.  
  465.          case USER_GROUP:
  466.            wsprintf((LPSTR)Temp,"GROUP %s", (LPSTR)InBuffer);
  467.            /* send GROUP command, expect single text line back */
  468.            AsyncCommand((LPSTR)Temp, USER_COMMAND_SUCCESS, USER_COMMAND_FAILURE,
  469.                         ASYNC_SINGLE_LINE);
  470.            break;
  471.  
  472.          /* get header by number */
  473.  
  474.          case USER_HEADER:
  475.            Article = wilParseDecimal((LPSTR)InBuffer);
  476.            wsprintf((LPSTR)Temp,"HEAD %lu", Article);
  477.            /* send HEAD command, expect multiple text lines back */
  478.            AsyncCommand((LPSTR)Temp, USER_COMMAND_SUCCESS, USER_COMMAND_FAILURE,
  479.                         ASYNC_MULTIPLE_LINES);
  480.            break;
  481.  
  482.          /* get article by number & save to disk */
  483.  
  484.          case USER_ARTICLE:
  485.            /* get article number */
  486.            Article = wilParseDecimal((LPSTR)InBuffer);
  487.            /* construct filename for article */
  488.            wsprintf((LPSTR)FileName,"%1lu.ART", Article);
  489.            wsprintf((LPSTR)Temp,"Saving article %lu to file '%s'",
  490.                     Article,(LPSTR)FileName);
  491.            DisplayLine((LPSTR)Temp);
  492.            /* open file for this article */
  493.            Handle = _lcreat((LPSTR)FileName,0);
  494.            if(Handle<0)
  495.              {DisplayString("Cannot create ");
  496.               DisplayLine((LPSTR)FileName);
  497.               Handle = 0;
  498.               POST_MSG(USER_COMMAND_FAILURE);
  499.               break;
  500.              }
  501.            /* send ARTICLE command, expect 1st line back */
  502.            wsprintf((LPSTR)Temp,"ARTICLE %1lu", Article);
  503.            AsyncCommand((LPSTR)Temp, USER_ART_READ_OK, USER_COMMAND_FAILURE,
  504.                         ASYNC_SINGLE_LINE);
  505.            break;
  506.  
  507.          case USER_ART_READ_OK:
  508.            /* read was successfull */
  509.            BufferPtr = AsyncGetBufPtr();
  510.            /* check if this is the last line */
  511.            if((*BufferPtr=='.')&&(*(BufferPtr+1)=='\r') )
  512.              {/* end of this article */
  513.               DisplayLine("[END]");
  514.               POST_MSG(USER_COMMAND_SUCCESS);
  515.               break;
  516.              }
  517.            /* write line to disk */
  518.            _lwrite(Handle, (LPSTR)BufferPtr, lstrlen((LPSTR)BufferPtr) );
  519.            /* read next line */
  520.            AsyncRead(USER_ART_READ_OK, USER_COMMAND_FAILURE, ASYNC_SINGLE_LINE);
  521.            break;
  522.  
  523.          /* command was successfull */
  524.  
  525.          case USER_COMMAND_SUCCESS:
  526.            if(Handle)
  527.              {_lclose(Handle);
  528.               Handle = 0;
  529.              }
  530.            AsyncSetEcho(EchoFlag);
  531.            ConnectedMenuState();
  532.            SetCursor(ArrowCursor);
  533.            break;
  534.  
  535.          /* command failed */
  536.  
  537.          case USER_COMMAND_FAILURE:
  538.            AsyncSetEcho(EchoFlag);
  539.            ConnectedMenuState();
  540.            SetCursor(ArrowCursor);
  541.            break;
  542.  
  543.          /* QUIT command successfull */
  544.  
  545.          case USER_QUIT_SUCCESS:
  546.             NotConnectedMenuState();
  547.             ConnectedFlag = FALSE;
  548.             break;
  549.         }
  550.       break;
  551.  
  552.     case WM_PAINT:
  553.       HideCaret(hMainWnd);
  554.       hDC = BeginPaint(hMainWnd, &ps);
  555.       SetMapMode(hDC,MM_ANISOTROPIC);
  556.       SelectObject(hDC, GetStockObject(OEM_FIXED_FONT) );
  557.       PaintMain(hDC,&ps);
  558.       EndPaint(hMainWnd,&ps);
  559.       SetCaretPos(PaintGetColPos(),PaintGetRowPos());
  560.       ShowCaret(hMainWnd);
  561.       break;
  562.  
  563.     case WM_DESTROY:
  564.       PostQuitMessage(0);
  565.       break;
  566.  
  567.    case WM_CHAR:
  568.      if(wParam==CR)
  569.        {/* user has completed input */
  570.         DestroyCaret();
  571.         DisplayChar(LF);
  572.         InBuffer[InBufLen] = '\0';
  573.         /* excute command associated with input buffer */
  574.         POST_MSG(InBufCmd);
  575.        }
  576.      else
  577.        {/* add char to input buffer */
  578.         Add2Buffer((char) wParam);
  579.        }
  580.      break;
  581.  
  582.     default:
  583.       return (DefWindowProc(hMainWnd, iMsg, wParam, lParam));
  584.    }
  585.  return 0;
  586.  
  587. } /* end MainWndProc */
  588.